S3保管したCloudTrailログに別アカウントのLambdaからアクセスする
こんにちは、虎塚です。
今回は、S3バケットに格納したCloudTrailログに、別のアカウントのAWS Lambdaからアクセスする方法をご紹介します。
前提となる構成
2つのAWSアカウントがあるとします。
- アカウントA: AWSアカウントID 000000000000
- アカウントB: AWSアカウントID 111111111111
アカウントAではCloudTrailログを有効にしていて、gz形式のログファイルをアカウントAのS3バケット に保管しています。アカウントBのLambdaファンクションから、このログファイルへアクセスして、getObjectでファイルを参照しようとしています。
S3バケットには、CloudTrailログの保存先として必要なバケットポリシーが設定されているものとします。次の公式ドキュメントにあるポリシーをそのまま使っていると考えてください。
さて、どのAWSリソースに対して、どのような権限を設定すれば、意図したアクセスができるでしょうか。
設定手順
アカウントA側での操作
CloudTrailログをS3バケットに保管している側のアカウントで、次の手順をおこないます。
1. IAMロールを作成
まず、アカウントAで、アカウントBにアクセスを提供するためのIAMロールを作成します。アカウントBのLambdaファンクションが、このロールを後ほど利用します。
AWS Management ConsoleのIAMダッシュボードを開き、ロール一覧で[Create New Role]ボタンを押します。次の設定でロールを作成します。
- Role Name: 任意 (cross-role-for-cloudtrail)
- Role Type: 「Provide access between AWS accounts you own」
- Account ID: アカウントBのAWSアカウントID (111111111111)
- Policy: 未選択
作成したロールのarnは、「arn:aws:iam::000000000000:role/cross-role-for-cloudtrail」のようになります。
2. IAMポリシーを作成
次に、アカウントAで、S3バケット (my-cloudtrail-bucket) へのアクセスを許可するIAMポリシーを作成します。
AWS Management ConsoleのIAMダッシュボードを開き、ポリシー一覧で[Create Policy]ボタンを押します。[Create Your Own Policy]を選んで、次の設定でポリシーを作成します。
- Policy Name: 任意 (S3GetAndListAccess)
- Policy Document: 次のとおり
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:Get*", "s3:List*" ], "Resource": "arn:aws:s3:::my-cloudtrail-bucket/*" } ] }
3. ポリシーをロールに適用
ステップ2で作成したポリシーを、ステップ1で作成したロールに適用します。
ロール一覧でcross-role-for-cloudtrailをダブルクリックして、[Permissions]タブの[Attach Policy]ボタンを押します。ポリシー一覧から、ステップ2で作成したポリシー (S3GetAndListAccess) を選択します。
アカウントB側での操作
もう片方のAWSアカウントで、次の手順をおこないます。
4. AssumeRole許可を定義したIAMポリシーを作成
次の設定でIAMポリシーを作成し、他のロールを引き受けるために必要な権限を定義します。
AWS Management ConsoleのIAMダッシュボードを開き、ポリシー一覧で[Create Policy]ボタンを押します。[Create Your Own Policy]を選んで、次の設定でポリシーを作成します。
- Policy Name: 任意 (AssumeRolePolicy)
- Policy Document: 次のとおり
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "sts:AssumeRole" ], "Resource": [ "*" ] } ] }
5. Lambdaファンクションの実行ロールを作成
この後作成するLambdaファンクションに適用するためのIAMロールを、アカウントBに作成します。
- Role Name: 任意 (cloudtrail-cross-access-lambda-role)
- Role Type: AWS Service Rolesの「AWS Lambda」を選択
- Policy: ステップ4で作成したポリシー (AssumeRolePolicy)
このロールは、ステップ6で作成するLambdaファンクションに適用するため、本来はステップ4で作成したポリシーに加えて、Lambdaファンクションの実行に必要な権限のポリシーも必要です。今回は、ステップ4で作成したポリシーだけで動くサンプルコードのため、後者を省略しました。
6. Lambdaファンクションの作成
最後に、アカウントBでLambdaファンクションを作成します。このLambdaファンクションは、アカウントAのS3バケットのオブジェクト(CloudTrailログ)に対して、GetObject APIを実行します。
Management ConsoleのLambdaダッシュボードで、[Create a Lambda function]ボタンを選択します。次の設定で、Lambdaファンクションを作成します。
- Select blueprint画面: 「s3-get-object-python」を選択
- Configure triggers画面: [Remove]ボタンを選択して、何も指定しない状態にする
- Name: 任意 (get-cloudtrail-in-s3)
- Runtime: Python 2.7
- Lambda function code: デフォルトのコードを削除して、次のコードをコピーアンドペーストする
import boto3 import os def lambda_handler(event, context): sts_client = boto3.client('sts') assumedRoleObject = sts_client.assume_role( RoleArn="arn:aws:iam::000000000000:role/cross-role-for-cloudtrail", RoleSessionName="AssumeRoleSession1" ) credentials = assumedRoleObject['Credentials'] s3_resource = boto3.resource( 's3', aws_access_key_id = credentials['AccessKeyId'], aws_secret_access_key = credentials['SecretAccessKey'], aws_session_token = credentials['SessionToken'], ) s3_resource.Object('my-cloudtrail-bucket', 'AWSLogs/000000000000/CloudTrail/ap-northeast-1/2016/08/25/000000000000_CloudTrail_ap-northeast-1_20160825T1310Z_XXXXXXXXXXXXXXXX.json.gz').download_file('/tmp/hoge.gz') files = os.listdir('/tmp/') for file in files: print file
コードの中で、ステップ1で作成したアカウントAのロールARN、CloudTrail用S3バケット名、特定のログファイル名の指定が必要です。
- Handler: lambda_function.lambda_handler
- Role: Choose an existing role
- Existing role: ステップ5で作成したロール (cloudtrail-cross-access-lambda-role)
- Memory (MB): 128
- Timeout: 5 sec
- VPC: no vpc
設定を保存したら、[Test]ボタンを押して実行します。
「null」が出力され、次のようなログを得られれば成功です。
START RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Version: $LATEST hoge.gz END RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx REPORT RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Duration: 2448.14 ms Billed Duration: 2500 ms Memory Size: 128 MB Max Memory Used: 41 MB
説明
なぜアカウントBのLambdaファンクションが、アカウントAのS3オブジェクトにアクセスできたかを、簡単に説明します。
アカウントBのLambdaファンクションでは、アカウントAのロールの認証情報を取得します(ステップ6)。これは、Lambdaファンクションに実行ロールを通してAssumeRole許可を与えていたため(ステップ4、5)、そしてアカウントAのロールでアカウントBを信頼するように設定していたため(ステップ1)、実現できました。
Lambdaファンクションが利用する一時的な認証情報 (STS) で可能な操作は、アカウントAのロールに対してポリシーで許可された操作(ステップ2、3)に限定されます。
おわりに
今回の設定は、クロスアカウントのためのロール引き受けと、AWS LambdaでのSTS利用がポイントでした。
それでは、また。